
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>序列化 Django 对象 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
    <link rel="next" title="Django 配置" href="settings.html" />
    <link rel="prev" title="性能和优化" href="performance.html" />



 
<script src="../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);</script>

  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../index.html">Home</a>  |
        <a title="Table of contents" href="../contents.html">Table of contents</a>  |
        <a title="Global index" href="../genindex.html">Index</a>  |
        <a title="Module index" href="../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="performance.html" title="性能和优化">previous</a>
     |
    <a href="index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="settings.html" title="Django 配置">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="topics-serialization">
            
  <div class="section" id="s-serializing-django-objects">
<span id="serializing-django-objects"></span><h1>序列化 Django 对象<a class="headerlink" href="#serializing-django-objects" title="永久链接至标题">¶</a></h1>
<p>Django 的序列化框架提供了一种将 Django 模型“翻译”为其他格式的机制。通常，这些其他格式将基于文本，并用于在网络上发送 Django 数据，但是序列化程序可以处理任何格式（无论是否基于文本）。</p>
<div class="admonition seealso">
<p class="first admonition-title">参见</p>
<p class="last">如果你只是想将表中的某些数据转换为序列化形式，你可以使用 <a class="reference internal" href="../ref/django-admin.html#django-admin-dumpdata"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">dumpdata</span></code></a> 管理命令。</p>
</div>
<div class="section" id="s-serializing-data">
<span id="serializing-data"></span><h2>序列化数据<a class="headerlink" href="#serializing-data" title="永久链接至标题">¶</a></h2>
<p>在最高层面，你可以像这样序列化数据：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.core</span> <span class="kn">import</span> <span class="n">serializers</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s2">&quot;xml&quot;</span><span class="p">,</span> <span class="n">SomeModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">())</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">serialize</span></code> 函数的参数是数据序列化的目标格式 （查看 <a class="reference internal" href="#id2">序列化格式</a>）和用来序列化的 <a class="reference internal" href="../ref/models/querysets.html#django.db.models.query.QuerySet" title="django.db.models.query.QuerySet"><code class="xref py py-class docutils literal notranslate"><span class="pre">QuerySet</span></code></a>。（实际上，第二个参数可以是任何生成 Django 模型实例的迭代器，但它几乎总是一个QuerySet）。</p>
<dl class="function">
<dt id="django.core.serializers.get_serializer">
<code class="descclassname">django.core.serializers.</code><code class="descname">get_serializer</code>(<em>format</em>)<a class="headerlink" href="#django.core.serializers.get_serializer" title="永久链接至目标">¶</a></dt>
<dd></dd></dl>

<p>你也可以直接使用序列化器对象：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">XMLSerializer</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">get_serializer</span><span class="p">(</span><span class="s2">&quot;xml&quot;</span><span class="p">)</span>
<span class="n">xml_serializer</span> <span class="o">=</span> <span class="n">XMLSerializer</span><span class="p">()</span>
<span class="n">xml_serializer</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">queryset</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">xml_serializer</span><span class="o">.</span><span class="n">getvalue</span><span class="p">()</span>
</pre></div>
</div>
<p>如果要将数据直接序列化到类似文件的对象（包括 <a class="reference internal" href="../ref/request-response.html#django.http.HttpResponse" title="django.http.HttpResponse"><code class="xref py py-class docutils literal notranslate"><span class="pre">HttpResponse</span></code></a>）这将很有用：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&quot;file.xml&quot;</span><span class="p">,</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">out</span><span class="p">:</span>
    <span class="n">xml_serializer</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">SomeModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span> <span class="n">stream</span><span class="o">=</span><span class="n">out</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">以未知 <a class="reference internal" href="#serialization-formats"><span class="std std-ref">格式</span></a> 调用 <a class="reference internal" href="#django.core.serializers.get_serializer" title="django.core.serializers.get_serializer"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_serializer()</span></code></a> 将引发 <code class="docutils literal notranslate"><span class="pre">django.core.serializers.SerializerDoesNotExist</span></code> 异常。</p>
</div>
<div class="section" id="s-subset-of-fields">
<span id="s-id1"></span><span id="subset-of-fields"></span><span id="id1"></span><h3>字段子集<a class="headerlink" href="#subset-of-fields" title="永久链接至标题">¶</a></h3>
<p>如果你只希望序列化字段的子集，则可以为序列化程序指定 <code class="docutils literal notranslate"><span class="pre">fields</span></code> 参数：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.core</span> <span class="kn">import</span> <span class="n">serializers</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s1">&#39;xml&#39;</span><span class="p">,</span> <span class="n">SomeModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span> <span class="n">fields</span><span class="o">=</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">,</span><span class="s1">&#39;size&#39;</span><span class="p">))</span>
</pre></div>
</div>
<p>在此示例中，将仅序列化每个模型的 <code class="docutils literal notranslate"><span class="pre">name</span></code> 和 <code class="docutils literal notranslate"><span class="pre">size</span></code> 属性。主键总是序列化为结果输出中的 <code class="docutils literal notranslate"><span class="pre">pk</span></code> 元素；它永远不会出现在 <code class="docutils literal notranslate"><span class="pre">fields</span></code> 部分。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">根据你的模型，你可能会发现无法反序列化一个仅序列化了其字段子集的模型。如果已序列化的对象未指定模型所需的所有字段，则反序列化器将无法保存反序列化的实例。</p>
</div>
</div>
<div class="section" id="s-inherited-models">
<span id="inherited-models"></span><h3>继承来的模型<a class="headerlink" href="#inherited-models" title="永久链接至标题">¶</a></h3>
<p>如果你有一个使用 <a class="reference internal" href="db/models.html#abstract-base-classes"><span class="std std-ref">抽象基类</span></a> 定义的模型，那么你不必做任何特殊的事情来序列化该模型。对要序列化的一个（或多个）对象调用序列化程序，输出将是序列化对象的完整表示形式。</p>
<p>但是，如果你有一个使用 <a class="reference internal" href="db/models.html#multi-table-inheritance"><span class="std std-ref">多表继承</span></a> 的模型， 则还需要序列化该模型的所有基类。这是因为只有在模型上本地定义的字段才会被序列化。例如，考虑以下模型：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Place</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">Restaurant</span><span class="p">(</span><span class="n">Place</span><span class="p">):</span>
    <span class="n">serves_hot_dogs</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<p>如果你只序列化 Restaurant 模型：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">data</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s1">&#39;xml&#39;</span><span class="p">,</span> <span class="n">Restaurant</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">())</span>
</pre></div>
</div>
<p>序列化输出上的字段将仅包含 <code class="docutils literal notranslate"><span class="pre">serves_hot_dogs</span></code> 属性。基类的 <code class="docutils literal notranslate"><span class="pre">name</span></code> 属性将被忽略。</p>
<p>为了完全序列化你的 <code class="docutils literal notranslate"><span class="pre">Restaurant</span></code> 实例，你还需要将 <code class="docutils literal notranslate"><span class="pre">Place</span></code> 模型序列化：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">all_objects</span> <span class="o">=</span> <span class="p">[</span><span class="o">*</span><span class="n">Restaurant</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span> <span class="o">*</span><span class="n">Place</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()]</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s1">&#39;xml&#39;</span><span class="p">,</span> <span class="n">all_objects</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="s-deserializing-data">
<span id="deserializing-data"></span><h2>反序列化数据<a class="headerlink" href="#deserializing-data" title="永久链接至标题">¶</a></h2>
<p>反序列化数据与序列化数据非常相似：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">serializers</span><span class="o">.</span><span class="n">deserialize</span><span class="p">(</span><span class="s2">&quot;xml&quot;</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">do_something_with</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
</pre></div>
</div>
<p>如你所见，<code class="docutils literal notranslate"><span class="pre">deserialize</span></code> 函数与 <code class="docutils literal notranslate"><span class="pre">serialize</span></code> 函数采用相同的格式参数，字符串或数据流，并返回一个迭代器。</p>
<p>不过，这里有点复杂。<code class="docutils literal notranslate"><span class="pre">deserialize</span></code> 迭代器返回的对象 <em>不是</em> 常规的 Django 对象。相反，它们是特殊的 <code class="docutils literal notranslate"><span class="pre">DeserializedObject</span></code> 实例，实例封装了一个已创建 -- 但未保存 -- 的对象和任何相关联的数据。</p>
<p>调用 <code class="docutils literal notranslate"><span class="pre">DeserializedObject.save()</span></code> 保存对象到数据库。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">如果序列化数据中的 <code class="docutils literal notranslate"><span class="pre">pk</span></code> 属性不存在或为 null，则会将新实例保存到数据库中。</p>
</div>
<p>这可以确保反序列化是一个非破坏性操作，即使序列化表示中的数据与数据库中当前的数据不匹配。通常，使用这些 <code class="docutils literal notranslate"><span class="pre">DeserializedObject</span></code> 实例看起来像：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">deserialized_object</span> <span class="ow">in</span> <span class="n">serializers</span><span class="o">.</span><span class="n">deserialize</span><span class="p">(</span><span class="s2">&quot;xml&quot;</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">object_should_be_saved</span><span class="p">(</span><span class="n">deserialized_object</span><span class="p">):</span>
        <span class="n">deserialized_object</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</div>
<p>换句话说，通常的用途是检查反序列化的对象，以确保它们“适合”保存。如果你信任数据源，则可以直接保存对象并继续前进。</p>
<p>Django 对象本身可以被像 <code class="docutils literal notranslate"><span class="pre">deserialized_object.object</span></code> 一样检查。如果模型中不存在序列化字段，将引发 <code class="docutils literal notranslate"><span class="pre">DeserializationError</span></code> 错误，除非将 <code class="docutils literal notranslate"><span class="pre">ignorenonexistent</span></code> 参数为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 传入：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">serializers</span><span class="o">.</span><span class="n">deserialize</span><span class="p">(</span><span class="s2">&quot;xml&quot;</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">ignorenonexistent</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-serialization-formats">
<span id="s-id2"></span><span id="serialization-formats"></span><span id="id2"></span><h2>序列化格式<a class="headerlink" href="#serialization-formats" title="永久链接至标题">¶</a></h2>
<p>Django 支持多种序列化格式，其中一些格式要求你安装第三方 Python 模块：</p>
<table class="docutils">
<colgroup>
<col width="14%" />
<col width="86%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">标识符</th>
<th class="head">信息</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">xml</span></code></td>
<td>序列化和反序列化为一种简单地 XML 方言。</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">json</span></code></td>
<td>序列化和反序列化为 <a class="reference external" href="https://json.org/">JSON</a>。</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">jsonl</span></code></td>
<td>Serializes to and from <a class="reference external" href="https://jsonlines.org/">JSONL</a>.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">yaml</span></code></td>
<td>序列化为 YAML（YAML 不是标记语言）。此序列化器仅在 <a class="reference external" href="https://pyyaml.org/">PyYAML</a> 安装后可用。</td>
</tr>
</tbody>
</table>
<div class="section" id="s-xml">
<span id="xml"></span><h3>XML<a class="headerlink" href="#xml" title="永久链接至标题">¶</a></h3>
<p>基本的 XML 序列化格式如下所示：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;django-objects version=&quot;1.0&quot;&gt;
    &lt;object pk=&quot;123&quot; model=&quot;sessions.session&quot;&gt;
        &lt;field type=&quot;DateTimeField&quot; name=&quot;expire_date&quot;&gt;2013-01-16T08:16:59.844560+00:00&lt;/field&gt;
        &lt;!-- ... --&gt;
    &lt;/object&gt;
&lt;/django-objects&gt;
</pre></div>
</div>
<p>序列化或反序列化的整个对象集合由一个包含多个 <code class="docutils literal notranslate"><span class="pre">&lt;object&gt;</span></code> - 元素的 <code class="docutils literal notranslate"><span class="pre">&lt;django-objects&gt;</span></code> - 标签标识。每个这样的对象都有两个属性：“pk”和“model”，后者由用点号分隔的 app 名称（“sessions”）和模型的小写名称（“session”）来代替。</p>
<p>对象的每个字段都序列化为一个具有“type”和“name”的 <code class="docutils literal notranslate"><span class="pre">&lt;field&gt;</span></code>- 元素 。元素的文本内容表示应该存储的值。</p>
<p>外键和其他关系字段的处理方式稍有不同：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&lt;object pk=&quot;27&quot; model=&quot;auth.permission&quot;&gt;
    &lt;!-- ... --&gt;
    &lt;field to=&quot;contenttypes.contenttype&quot; name=&quot;content_type&quot; rel=&quot;ManyToOneRel&quot;&gt;9&lt;/field&gt;
    &lt;!-- ... --&gt;
&lt;/object&gt;
</pre></div>
</div>
<p>在本例中，我们指定具有 PK 27 的 <code class="docutils literal notranslate"><span class="pre">auth.Permission</span></code> 对象有一个指向 PK 9 的 <code class="docutils literal notranslate"><span class="pre">contenttypes.ContentType</span></code> 实例的外键。</p>
<p>多对多关系是为绑定它们的模型导出的。例如，<code class="docutils literal notranslate"><span class="pre">auth.User</span></code> 模型与 <code class="docutils literal notranslate"><span class="pre">auth.Permission</span></code> 模型有这样的关系：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&lt;object pk=&quot;1&quot; model=&quot;auth.user&quot;&gt;
    &lt;!-- ... --&gt;
    &lt;field to=&quot;auth.permission&quot; name=&quot;user_permissions&quot; rel=&quot;ManyToManyRel&quot;&gt;
        &lt;object pk=&quot;46&quot;&gt;&lt;/object&gt;
        &lt;object pk=&quot;47&quot;&gt;&lt;/object&gt;
    &lt;/field&gt;
&lt;/object&gt;
</pre></div>
</div>
<p>此示例将给定用户与 PK 46 和 47 的权限模型链接起来。</p>
<div class="admonition-control-characters admonition">
<p class="first admonition-title">控制字符</p>
<p class="last">如果要序列化的内容包含 XML 1.0 标准不接受的控制字符，则序列化将失败，并出现 <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#ValueError" title="(在 Python v3.10)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ValueError</span></code></a> 异常。另请阅读 W3C 对 <a class="reference external" href="https://www.w3.org/International/questions/qa-controls">HTML, XHTML, XML and Control Codes</a> 的解释。</p>
</div>
</div>
<div class="section" id="s-serialization-formats-json">
<span id="s-id3"></span><span id="serialization-formats-json"></span><span id="id3"></span><h3>JSON<a class="headerlink" href="#serialization-formats-json" title="永久链接至标题">¶</a></h3>
<p>当与之前相同的示例数据保持不变时，它将按以下方式序列化为 JSON：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span>
    <span class="p">{</span>
        <span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="s2">&quot;4b678b301dfd8a4e0dad910de3ae245b&quot;</span><span class="p">,</span>
        <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;sessions.session&quot;</span><span class="p">,</span>
        <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s2">&quot;expire_date&quot;</span><span class="p">:</span> <span class="s2">&quot;2013-01-16T08:16:59.844Z&quot;</span><span class="p">,</span>
            <span class="o">...</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">]</span>
</pre></div>
</div>
<p>这里的格式比 XML 简单一些。整个集合只是表示为一个数组，对象由具有三个属性的 JSON 对象表示：“pk”，“model”和“fields”。“fields”又是一个对象，其中分别包含每个字段的名称和值作为属性和属性值。</p>
<p>外键将链接对象的 PK 作为属性值。多对多关系对于定义它们的模型进行了序列化，并表示为 PK 列表。</p>
<p>请注意，并非所有的Django输出都可以不经修改地传递到 <a class="reference external" href="https://docs.python.org/3/library/json.html#module-json" title="(在 Python v3.10)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">json</span></code></a>。例如，如果要序列化对象中的某个自定义类型，则必须为其编写一个自定义 <a class="reference external" href="https://docs.python.org/3/library/json.html#module-json" title="(在 Python v3.10)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">json</span></code></a> 编码器。这样的方法会奏效的：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.core.serializers.json</span> <span class="kn">import</span> <span class="n">DjangoJSONEncoder</span>

<span class="k">class</span> <span class="nc">LazyEncoder</span><span class="p">(</span><span class="n">DjangoJSONEncoder</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">YourCustomType</span><span class="p">):</span>
            <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">default</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
</pre></div>
</div>
<p>你可以将 <code class="docutils literal notranslate"><span class="pre">cls=LazyEncoder</span></code> 传入 <code class="docutils literal notranslate"><span class="pre">serializers.serialize()</span></code> 函数：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.core.serializers</span> <span class="kn">import</span> <span class="n">serialize</span>

<span class="n">serialize</span><span class="p">(</span><span class="s1">&#39;json&#39;</span><span class="p">,</span> <span class="n">SomeModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span> <span class="bp">cls</span><span class="o">=</span><span class="n">LazyEncoder</span><span class="p">)</span>
</pre></div>
</div>
<p>还要注意 GeoDjango 提供了一个 <a class="reference internal" href="../ref/contrib/gis/serializers.html"><span class="doc">定制的 GeoJSON 序列化器</span></a>.</p>
<div class="versionchanged">
<span class="title">Changed in Django 3.1:</span> <p>所有的数据现在都使用 Unicode 转储。如果你需要之前的行为，传入 <code class="docutils literal notranslate"><span class="pre">ensure_ascii=True</span></code> 给 <code class="docutils literal notranslate"><span class="pre">serializers.serialize()</span></code> 函数。</p>
</div>
<div class="section" id="s-djangojsonencoder">
<span id="djangojsonencoder"></span><h4><code class="docutils literal notranslate"><span class="pre">DjangoJSONEncoder</span></code><a class="headerlink" href="#djangojsonencoder" title="永久链接至标题">¶</a></h4>
<dl class="class">
<dt id="django.core.serializers.json.DjangoJSONEncoder">
<em class="property">class </em><code class="descclassname">django.core.serializers.json.</code><code class="descname">DjangoJSONEncoder</code><a class="headerlink" href="#django.core.serializers.json.DjangoJSONEncoder" title="永久链接至目标">¶</a></dt>
<dd></dd></dl>

<p>JSON 序列化器使用 <code class="docutils literal notranslate"><span class="pre">DjangoJSONEncoder</span></code> 进行编码。作为 <a class="reference external" href="https://docs.python.org/3/library/json.html#json.JSONEncoder" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">JSONEncoder</span></code></a> 的子类，它可以处理这些附加类型：</p>
<dl class="docutils">
<dt><a class="reference external" href="https://docs.python.org/3/library/datetime.html#datetime.datetime" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">datetime</span></code></a></dt>
<dd>格式为 <code class="docutils literal notranslate"><span class="pre">YYYY-MM-DDTHH:mm:ss.sssZ</span></code> 或 <code class="docutils literal notranslate"><span class="pre">YYYY-MM-DDTHH:mm:ss.sss+HH:MM</span></code> 的字符串，如 <a class="reference external" href="https://262.ecma-international.org/5.1/#sec-15.9.1.15">ECMA-262</a> 中定义。</dd>
<dt><a class="reference external" href="https://docs.python.org/3/library/datetime.html#datetime.date" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">date</span></code></a></dt>
<dd>格式为 <code class="docutils literal notranslate"><span class="pre">YYYY-MM-DD</span></code> 的字符串，如 <a class="reference external" href="https://262.ecma-international.org/5.1/#sec-15.9.1.15">ECMA-262</a> 中定义。</dd>
<dt><a class="reference external" href="https://docs.python.org/3/library/datetime.html#datetime.time" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">time</span></code></a></dt>
<dd>格式为 <code class="docutils literal notranslate"><span class="pre">HH:MM:ss.sss</span></code> 的字符串，如 <a class="reference external" href="https://262.ecma-international.org/5.1/#sec-15.9.1.15">ECMA-262</a> 中定义。</dd>
<dt><a class="reference external" href="https://docs.python.org/3/library/datetime.html#datetime.timedelta" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">timedelta</span></code></a></dt>
<dd>代表 ISO-8601 中定义的持续时间的字符串。例如，<code class="docutils literal notranslate"><span class="pre">timedelta(days=1,</span> <span class="pre">hours=2,</span> <span class="pre">seconds=3.4)</span></code> 代表 <code class="docutils literal notranslate"><span class="pre">'P1DT02H00M03.400000S'</span></code>。</dd>
<dt><a class="reference external" href="https://docs.python.org/3/library/decimal.html#decimal.Decimal" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">Decimal</span></code></a>，<code class="docutils literal notranslate"><span class="pre">Promise</span></code> （ <code class="docutils literal notranslate"><span class="pre">django.utils.functional.lazy()</span></code> 对象），<a class="reference external" href="https://docs.python.org/3/library/uuid.html#uuid.UUID" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">UUID</span></code></a></dt>
<dd>对象的字符串表示形式。</dd>
</dl>
</div>
</div>
<div class="section" id="s-serialization-formats-jsonl">
<span id="s-id4"></span><span id="serialization-formats-jsonl"></span><span id="id4"></span><h3>JSONL<a class="headerlink" href="#serialization-formats-jsonl" title="永久链接至标题">¶</a></h3>
<div class="versionadded">
<span class="title">New in Django 3.2.</span> </div>
<p><em>JSONL</em> stands for <em>JSON Lines</em>. With this format, objects are separated by new
lines, and each line contains a valid JSON object. JSONL serialized data looks
like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="s2">&quot;4b678b301dfd8a4e0dad910de3ae245b&quot;</span><span class="p">,</span> <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;sessions.session&quot;</span><span class="p">,</span> <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span><span class="o">...</span><span class="p">}}</span>
<span class="p">{</span><span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="s2">&quot;88bea72c02274f3c9bf1cb2bb8cee4fc&quot;</span><span class="p">,</span> <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;sessions.session&quot;</span><span class="p">,</span> <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span><span class="o">...</span><span class="p">}}</span>
<span class="p">{</span><span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="s2">&quot;9cf0e26691b64147a67e2a9f06ad7a53&quot;</span><span class="p">,</span> <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;sessions.session&quot;</span><span class="p">,</span> <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span><span class="o">...</span><span class="p">}}</span>
</pre></div>
</div>
<p>JSONL can be useful for populating large databases, since the data can be
processed line by line, rather than being loaded into memory all at once.</p>
</div>
<div class="section" id="s-yaml">
<span id="yaml"></span><h3>YAML<a class="headerlink" href="#yaml" title="永久链接至标题">¶</a></h3>
<p>YAML 序列化看起来与 JSON 非常相似。对象列表通过映射键“pk”，“model”和“fields”为序列进行序列化。每个字段还是一个映射，键为字段名称，值为字段值：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>-   fields: {expire_date: !!timestamp &#39;2013-01-16 08:16:59.844560+00:00&#39;}
    model: sessions.session
    pk: 4b678b301dfd8a4e0dad910de3ae245b
</pre></div>
</div>
<p>引用字段再次由 PK 或 PK 序列表示。</p>
<div class="versionchanged">
<span class="title">Changed in Django 3.1:</span> <p>所有的数据现在都使用 Unicode 转储。如果你需要之前的行为，传入 <code class="docutils literal notranslate"><span class="pre">ensure_ascii=True</span></code> 给 <code class="docutils literal notranslate"><span class="pre">serializers.serialize()</span></code> 函数。</p>
</div>
</div>
</div>
<div class="section" id="s-natural-keys">
<span id="s-topics-serialization-natural-keys"></span><span id="natural-keys"></span><span id="topics-serialization-natural-keys"></span><h2>自然键<a class="headerlink" href="#natural-keys" title="永久链接至标题">¶</a></h2>
<p>外键和多对多关系的默认序列化策略是序列化在关系中对象主键的值。这种策略对大多数对象都有效，但在某些情况下可能会造成困难。</p>
<p>考虑一个对象列表，这些对象的外键引用 <a class="reference internal" href="../ref/contrib/contenttypes.html#django.contrib.contenttypes.models.ContentType" title="django.contrib.contenttypes.models.ContentType"><code class="xref py py-class docutils literal notranslate"><span class="pre">ContentType</span></code></a>。如果要序列化引用内容类型的对象，那么首先需要有一种引用该内容类型的方法。由于 <code class="docutils literal notranslate"><span class="pre">ContentType</span></code> 对象是由 Django 在数据库同步过程中自动创建的，所以给定内容类型的主键不容易预测；这将取决于 <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">migrate</span></code></a> 的执行方式和时间。对于自动生成对象的所有模型都是如此，特别是包括 <a class="reference internal" href="../ref/contrib/auth.html#django.contrib.auth.models.Permission" title="django.contrib.auth.models.Permission"><code class="xref py py-class docutils literal notranslate"><span class="pre">Permission</span></code></a>，<a class="reference internal" href="../ref/contrib/auth.html#django.contrib.auth.models.Group" title="django.contrib.auth.models.Group"><code class="xref py py-class docutils literal notranslate"><span class="pre">Group</span></code></a>，和 <a class="reference internal" href="../ref/contrib/auth.html#django.contrib.auth.models.User" title="django.contrib.auth.models.User"><code class="xref py py-class docutils literal notranslate"><span class="pre">User</span></code></a>。</p>
<div class="admonition warning">
<p class="first admonition-title">警告</p>
<p class="last">永远不要在辅助工具和其它序列化数据中包含自动生成的对象。偶尔，辅助工具中加载的主键可能与数据库中的相匹配而加载的辅助工具可能没有起到任何作用。更可能的情况是它们并不匹配，辅助工具将加载失败，并出现 <a class="reference internal" href="../ref/exceptions.html#django.db.IntegrityError" title="django.db.IntegrityError"><code class="xref py py-class docutils literal notranslate"><span class="pre">IntegrityError</span></code></a> 错误。</p>
</div>
<p>还有一个便捷性的问题。整数 id 并不总是引用对象的最方便方式；有时，更自然的引用会有所帮助。</p>
<p>正是由于这些原因 Django 提供了 <em>自然键</em>。自然键是一组值，可以用来唯一标识对象实例，而不使用主键值。</p>
<div class="section" id="s-deserialization-of-natural-keys">
<span id="deserialization-of-natural-keys"></span><h3>自然键反序列化<a class="headerlink" href="#deserialization-of-natural-keys" title="永久链接至标题">¶</a></h3>
<p>考虑以下两种模型：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">Person</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">first_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">last_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>

    <span class="n">birthdate</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">()</span>

    <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
        <span class="n">unique_together</span> <span class="o">=</span> <span class="p">[[</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;last_name&#39;</span><span class="p">]]</span>

<span class="k">class</span> <span class="nc">Book</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">author</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">Person</span><span class="p">,</span> <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">CASCADE</span><span class="p">)</span>
</pre></div>
</div>
<p>通常，序列化 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 会使用一个整数来指代作者。例如，在 JSON 中，一个 Book 可以序列化为：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="p">{</span>
    <span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;store.book&quot;</span><span class="p">,</span>
    <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Mostly Harmless&quot;</span><span class="p">,</span>
        <span class="s2">&quot;author&quot;</span><span class="p">:</span> <span class="mi">42</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="o">...</span>
</pre></div>
</div>
<p>这不是一个特别自然的方式来指代作者。它要求你知道作者的主键值；它还要求这个主键值是稳定的和可预测的。</p>
<p>然而，如果我们向 Person 添加自然键处理，则辅助工具将变得更加人性化。要添加自然键处理， 你可以为 Person 定义一个有着 <code class="docutils literal notranslate"><span class="pre">get_by_natural_key()</span></code> 方法的默认 Manager。对于 Person 来说，一个好的自然键可能是姓名：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">PersonManager</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Manager</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">get_by_natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">first_name</span><span class="p">,</span> <span class="n">last_name</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">first_name</span><span class="o">=</span><span class="n">first_name</span><span class="p">,</span> <span class="n">last_name</span><span class="o">=</span><span class="n">last_name</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">Person</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">first_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">last_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">birthdate</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">()</span>

    <span class="n">objects</span> <span class="o">=</span> <span class="n">PersonManager</span><span class="p">()</span>

    <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
        <span class="n">unique_together</span> <span class="o">=</span> <span class="p">[[</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;last_name&#39;</span><span class="p">]]</span>
</pre></div>
</div>
<p>现在书籍可以使用自然键来指代 <code class="docutils literal notranslate"><span class="pre">Person</span></code> 对象：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="p">{</span>
    <span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;store.book&quot;</span><span class="p">,</span>
    <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Mostly Harmless&quot;</span><span class="p">,</span>
        <span class="s2">&quot;author&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Douglas&quot;</span><span class="p">,</span> <span class="s2">&quot;Adams&quot;</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="o">...</span>
</pre></div>
</div>
<p>当你试图加载此序列化数据时，Django 将使用 <code class="docutils literal notranslate"><span class="pre">get_by_natural_key()</span></code> 方法将 <code class="docutils literal notranslate"><span class="pre">[&quot;Douglas&quot;,</span> <span class="pre">&quot;Adams&quot;]</span></code> 解析为 <code class="docutils literal notranslate"><span class="pre">Person</span></code> 对象实际的主键。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">无论使用什么字段作为自然键，都必须能够唯一地标识对象。这通常意味着你的模型将为你的自然键中的一个或多个字段使用unique子句 （unique=True 在单个字段上，或 <code class="docutils literal notranslate"><span class="pre">unique_together</span></code> 在多个字段上）。但是，不需要在数据库级别强制执行唯一性。如果你确定一组字段实际上是唯一的，那么仍然可以将这些字段用作自然键。</p>
</div>
<p>对没有主键的对象的反序列化将始终检查模型的管理器是否具有 <code class="docutils literal notranslate"><span class="pre">get_by_natural_key()</span></code> 方法，如果有，则使用它填充反序列化对象的主键。</p>
</div>
<div class="section" id="s-serialization-of-natural-keys">
<span id="serialization-of-natural-keys"></span><h3>自然键序列化<a class="headerlink" href="#serialization-of-natural-keys" title="永久链接至标题">¶</a></h3>
<p>那么如何在序列化对象时让 Django 发出自然键？首先，你需要添加另一种方法，这一次是向模型本身添加：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Person</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">first_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">last_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">birthdate</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">()</span>

    <span class="n">objects</span> <span class="o">=</span> <span class="n">PersonManager</span><span class="p">()</span>

    <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
        <span class="n">unique_together</span> <span class="o">=</span> <span class="p">[[</span><span class="s1">&#39;first_name&#39;</span><span class="p">,</span> <span class="s1">&#39;last_name&#39;</span><span class="p">]]</span>

    <span class="k">def</span> <span class="nf">natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">first_name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_name</span><span class="p">)</span>
</pre></div>
</div>
<p>该方法应该始终返回一个自然键元组——在本例中为 <code class="docutils literal notranslate"><span class="pre">(first</span> <span class="pre">name,</span> <span class="pre">last</span> <span class="pre">name)</span></code>。接着当你调用 <code class="docutils literal notranslate"><span class="pre">serializers.serialize()</span></code> 时，提供 <code class="docutils literal notranslate"><span class="pre">use_natural_foreign_keys=True</span></code> 或 <code class="docutils literal notranslate"><span class="pre">use_natural_primary_keys=True</span></code> 参数：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s1">&#39;json&#39;</span><span class="p">,</span> <span class="p">[</span><span class="n">book1</span><span class="p">,</span> <span class="n">book2</span><span class="p">],</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="gp">... </span>     <span class="n">use_natural_foreign_keys</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">use_natural_primary_keys</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>当指定 <code class="docutils literal notranslate"><span class="pre">use_natural_foreign_keys=True</span></code> 时，Django 将使用 <code class="docutils literal notranslate"><span class="pre">natural_key()</span></code> 方法将任何外键引用序列化为定义该方法的类型的对象。</p>
<p>当指定 <code class="docutils literal notranslate"><span class="pre">use_natural_primary_keys=True</span></code> 时，Django 不会在该对象的序列化数据中提供主键，因为它可以在反序列化期间进行计算：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="p">{</span>
    <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;store.person&quot;</span><span class="p">,</span>
    <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s2">&quot;first_name&quot;</span><span class="p">:</span> <span class="s2">&quot;Douglas&quot;</span><span class="p">,</span>
        <span class="s2">&quot;last_name&quot;</span><span class="p">:</span> <span class="s2">&quot;Adams&quot;</span><span class="p">,</span>
        <span class="s2">&quot;birth_date&quot;</span><span class="p">:</span> <span class="s2">&quot;1952-03-11&quot;</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="o">...</span>
</pre></div>
</div>
<p>当需要将序列化数据加载到现有数据库中，并且无法保证序列化的主键值尚未使用，并且不需要确保反序列化对象保留相同的主键时，这一点非常有用。</p>
<p>如果你使用 <a class="reference internal" href="../ref/django-admin.html#django-admin-dumpdata"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">dumpdata</span></code></a> 生成序列化数据，使用 <a class="reference internal" href="../ref/django-admin.html#cmdoption-dumpdata-natural-foreign"><code class="xref std std-option docutils literal notranslate"><span class="pre">dumpdata</span> <span class="pre">--natural-foreign</span></code></a> 和 <a class="reference internal" href="../ref/django-admin.html#cmdoption-dumpdata-natural-primary"><code class="xref std std-option docutils literal notranslate"><span class="pre">dumpdata</span> <span class="pre">--natural-primary</span></code></a> 命令行标志生成自然键。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p>你不需要同时定义 <code class="docutils literal notranslate"><span class="pre">natural_key()</span></code> 和 <code class="docutils literal notranslate"><span class="pre">get_by_natural_key()</span></code>。如果你不想要 Django 在序列化期间输出自然键，但希望保留加载自然键的能力，那你可以选择不实现 <code class="docutils literal notranslate"><span class="pre">natural_key()</span></code> 方法。</p>
<p class="last">相反，如果（出于某些奇怪的原因）你想要 Django 在序列化时输出自然键，但是 <em>不</em> 加载那些键值，只需要不定义 <code class="docutils literal notranslate"><span class="pre">get_by_natural_key()</span></code> 方法。</p>
</div>
</div>
<div class="section" id="s-natural-keys-and-forward-references">
<span id="s-id5"></span><span id="natural-keys-and-forward-references"></span><span id="id5"></span><h3>自然键和前向引用<a class="headerlink" href="#natural-keys-and-forward-references" title="永久链接至标题">¶</a></h3>
<p>有时当你使用 <a class="reference internal" href="#topics-serialization-natural-keys"><span class="std std-ref">自然外键</span></a> 时，您需要反序列化数据，其中一个对象的外键引用了另一个尚未反序列化的对象。这称之为“前向引用”。</p>
<p>例如，假设辅助工具中有以下对象：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="p">{</span>
    <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;store.book&quot;</span><span class="p">,</span>
    <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Mostly Harmless&quot;</span><span class="p">,</span>
        <span class="s2">&quot;author&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Douglas&quot;</span><span class="p">,</span> <span class="s2">&quot;Adams&quot;</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">},</span>
<span class="o">...</span>
<span class="p">{</span>
    <span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="s2">&quot;store.person&quot;</span><span class="p">,</span>
    <span class="s2">&quot;fields&quot;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s2">&quot;first_name&quot;</span><span class="p">:</span> <span class="s2">&quot;Douglas&quot;</span><span class="p">,</span>
        <span class="s2">&quot;last_name&quot;</span><span class="p">:</span> <span class="s2">&quot;Adams&quot;</span>
    <span class="p">}</span>
<span class="p">},</span>
<span class="o">...</span>
</pre></div>
</div>
<p>为了处理这种情况，你需要将 <code class="docutils literal notranslate"><span class="pre">handle_forward_references=True</span></code> 传入 <code class="docutils literal notranslate"><span class="pre">serializers.deserialize()</span></code>。这将在 <code class="docutils literal notranslate"><span class="pre">DeserializedObject</span></code> 实例上设置 <code class="docutils literal notranslate"><span class="pre">deferred_fields</span></code> 属性。你需要保持追踪该属性不是 <code class="docutils literal notranslate"><span class="pre">None</span></code> 的 <code class="docutils literal notranslate"><span class="pre">DeserializedObject</span></code> 实例并在之后调用它们的 <code class="docutils literal notranslate"><span class="pre">save_deferred_fields()</span></code>。</p>
<p>典型用法如下：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">objs_with_deferred_fields</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">serializers</span><span class="o">.</span><span class="n">deserialize</span><span class="p">(</span><span class="s1">&#39;xml&#39;</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">handle_forward_references</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
    <span class="n">obj</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
    <span class="k">if</span> <span class="n">obj</span><span class="o">.</span><span class="n">deferred_fields</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
        <span class="n">objs_with_deferred_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>

<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">objs_with_deferred_fields</span><span class="p">:</span>
    <span class="n">obj</span><span class="o">.</span><span class="n">save_deferred_fields</span><span class="p">()</span>
</pre></div>
</div>
<p>要使其工作，引用模型上的 <code class="docutils literal notranslate"><span class="pre">ForeignKey</span></code> 必须具有 <code class="docutils literal notranslate"><span class="pre">null=True</span></code>。</p>
</div>
<div class="section" id="s-dependencies-during-serialization">
<span id="dependencies-during-serialization"></span><h3>序列化期间的依赖项<a class="headerlink" href="#dependencies-during-serialization" title="永久链接至标题">¶</a></h3>
<p>通过注意辅助工具中中对象的顺序，通常可以避免显式地处理前向引用。</p>
<p>为了帮助实现这一点，在序列化标准主键对象之前，使用 <a class="reference internal" href="../ref/django-admin.html#cmdoption-dumpdata-natural-foreign"><code class="xref std std-option docutils literal notranslate"><span class="pre">dumpdata</span> <span class="pre">--natural-foreign</span></code></a> 选项对 <a class="reference internal" href="../ref/django-admin.html#django-admin-dumpdata"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">dumpdata</span></code></a>  的调用将使用 <code class="docutils literal notranslate"><span class="pre">natural_key()</span></code> 方法对任何模型进行序列化。</p>
<p>但是，这可能并不总是足够的。如果您的自然键引用了另一个对象（通过使用外键或另一个对象的自然键作为自然键的一部分），那么你需要确保自然键所依赖的对象出现在序列化数据中在自然键要求它们之前。</p>
<p>要控制此顺序，你可以在 <code class="docutils literal notranslate"><span class="pre">natural_key()</span></code> 方法中定义依赖。为此可以在  <code class="docutils literal notranslate"><span class="pre">natural_key()</span></code> 方法本身上设置一个 <code class="docutils literal notranslate"><span class="pre">dependencies</span></code> 属性。</p>
<p>例如，让我们为上面示例中的 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 模型添加一个自然键：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Book</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
    <span class="n">author</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">Person</span><span class="p">,</span> <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">CASCADE</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,)</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">natural_key</span><span class="p">()</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">Book</span></code> 的自然键是书名和作者的组合。这意味着 <code class="docutils literal notranslate"><span class="pre">Person</span></code> 必须在 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 之前序列化。为了定义这个依赖，我们增加一行：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,)</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">natural_key</span><span class="p">()</span>
<span class="n">natural_key</span><span class="o">.</span><span class="n">dependencies</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;example_app.person&#39;</span><span class="p">]</span>
</pre></div>
</div>
<p>这个定义确保了所有 <code class="docutils literal notranslate"><span class="pre">Person</span></code> 对象在任何 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 对象之前序列化。反过来，任何对象引用了 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 都将在 <code class="docutils literal notranslate"><span class="pre">Person</span></code> 和 <code class="docutils literal notranslate"><span class="pre">Book</span></code> 被序列化完后再序列化。</p>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">序列化 Django 对象</a><ul>
<li><a class="reference internal" href="#serializing-data">序列化数据</a><ul>
<li><a class="reference internal" href="#subset-of-fields">字段子集</a></li>
<li><a class="reference internal" href="#inherited-models">继承来的模型</a></li>
</ul>
</li>
<li><a class="reference internal" href="#deserializing-data">反序列化数据</a></li>
<li><a class="reference internal" href="#serialization-formats">序列化格式</a><ul>
<li><a class="reference internal" href="#xml">XML</a></li>
<li><a class="reference internal" href="#serialization-formats-json">JSON</a><ul>
<li><a class="reference internal" href="#djangojsonencoder"><code class="docutils literal notranslate"><span class="pre">DjangoJSONEncoder</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#serialization-formats-jsonl">JSONL</a></li>
<li><a class="reference internal" href="#yaml">YAML</a></li>
</ul>
</li>
<li><a class="reference internal" href="#natural-keys">自然键</a><ul>
<li><a class="reference internal" href="#deserialization-of-natural-keys">自然键反序列化</a></li>
<li><a class="reference internal" href="#serialization-of-natural-keys">自然键序列化</a></li>
<li><a class="reference internal" href="#natural-keys-and-forward-references">自然键和前向引用</a></li>
<li><a class="reference internal" href="#dependencies-during-serialization">序列化期间的依赖项</a></li>
</ul>
</li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="performance.html"
                        title="上一章">性能和优化</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="settings.html"
                        title="下一章">Django 配置</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../_sources/topics/serialization.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="performance.html" title="性能和优化">previous</a>
     |
    <a href="index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="settings.html" title="Django 配置">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>